#include "SqlQuery.h"
#include <algorithm>
#include <stdio.h>

SqlQuery::SqlQuery(MYSQL *conn)
{
    m_conn = conn;
}

bool SqlQuery::exec(const string &sql)
{
    // 查询前各成员变量初始化
    m_res.clear();
    m_fields.clear();
    m_errorText.clear();

    // 执行错误
    if (mysql_query(m_conn, sql.data()) != 0)
    {
        m_errorText = mysql_error(m_conn); // 记录错误信息
        return false;
    }

    // 判断是否是查询语句,如果是查询语句,才要对接下来的结果集进行操作,(否则更新、删除后对结果集操作会产生段错误)
    if (!isSelect(sql))
        return true;

    MYSQL_RES *res = mysql_store_result(m_conn); // 获取查询的结果集
    int rows = mysql_num_rows(res);              // 获取结果集的行数
    int cols = mysql_num_fields(res);            // 获取结果集的列数
    // 将查询结果装入vector容器
    for (int i = 0; i < rows; i++)
    {
        /* 
        如果 mysql_fetch_row() 返回的 MYSQL_ROW 中某个字段是 NULL，则对应的 row[j] 指针将会是 NULL。直接尝试访问或转换 NULL 指针会导致程序崩溃。
        解决办法是判断是否为空指针，如果为空指针，那么就添加为空字符
        */ 
        // 取出一行结果集
        MYSQL_ROW row = mysql_fetch_row(res);
        vector<string> tmp;
        for (int j = 0; j < cols; j++) // 遍历这一行的每一列
        {
            if(row[j] != NULL)
                tmp.push_back(row[j]);
            else
                tmp.push_back("");
        }
            
        m_res.push_back(tmp);
    }

    MYSQL_FIELD *fields = mysql_fetch_field(res); // 获取结果集的列名(一个结构体数组,用其成员name获得列名)
                                                  // 将结果集列名装入vector容器,记录列名下标
    for (int i = 0; i < cols; i++)
        m_fields.push_back(fields[i].name);

    // 释放结果集
    mysql_free_result(res);

    return true;
}

bool SqlQuery::isSelect(const string &sql)
{
    string tmp = sql;
    int pos = tmp.find(" ");
    tmp = tmp.substr(0, pos);
    transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower); // 字符串转小写
    if (tmp == "select")
        return true;
    return false;
}
